package thinkinjava4.ch15_generics;

public class Wildcards {
    static void rawArgs(Holder holder, Object arg) {
        holder.set(arg);//Warming
        holder.set(new Wildcards());
    }

    static void unboundedArg(Holder<?> holder, Object arg) {
//        holder.set(arg);//Error
//        holder.set(new Wildcards());
        Object obj = holder.get();
    }

    static <T> T exact1(Holder<T> holder) {
        T t = holder.get();
        return t;
    }

    static <T> T exact2(Holder<T> holder, T arg) {
        holder.set(arg);
        T t = holder.get();
        return t;
    }

    /**
     * holder持有类型是T的子类
     * set方法Error的原因是：T赋值给T的子类可能发生向下转型，如 Fruit->Apple
     *
     * @param holder
     * @param arg
     * @param <T>
     * @return
     */
    static <T> T wildSubtype(Holder<? extends T> holder, T arg) {
//        holder.set(arg);//Error
        T t = holder.get();
        return t;
    }

    /**
     * holder持有类型是T的超类
     * get方法Error的原因是：当前类型是T holder中的类型是T的基类，可能会发生向下转型
     *
     * @param holder
     * @param arg
     * @param <T>
     */
    static <T> void wildSupertype(Holder<? super T> holder, T arg) {
        holder.set(arg);
//        T t=holder.get();//Error
        Object obj = holder.get();
    }

    public static void main(String[] args) {
        Holder raw = new Holder();
        Holder<Long> qualified = new Holder<>();
        Holder<?> unbounded = new Holder<>();
        Holder<? extends Long> bounded = new Holder<>();
        Long lng = 1L;
        rawArgs(raw, lng);
        rawArgs(qualified, lng);
        rawArgs(unbounded, lng);
        rawArgs(bounded, lng);

        unboundedArg(raw, lng);
        unboundedArg(qualified, lng);
        unboundedArg(unbounded, lng);
        unboundedArg(bounded, lng);

        Object r1 = exact1(raw);//Warnings
        Long r2 = exact1(qualified);
        Object r3 = exact1(unbounded);
        Long r4 = exact1(bounded);

        Long r5 = exact2(raw, lng);
        Long r6 = exact2(qualified, lng);
//        Long r7 = exact2(unbounded, lng);//Error
//        Long r8 = exact2(bounded, lng);//Error

        Long r9 = wildSubtype(raw, lng);
        Long r10 = wildSubtype(qualified, lng);
        //OK, but can only return Object
        Object r11 = wildSubtype(unbounded, lng);//<Object>  <? extends Object>
        Long r12 = wildSubtype(bounded, lng);

        wildSupertype(raw, lng);
        wildSupertype(qualified, lng);
//        wildSupertype(unbounded, lng);//Error <?>!=<? super T>
//        wildSupertype(bounded, lng);//Error <? extends Long> != <? super T>
    }
}
